package com.mach.platform.utils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.cglib.beans.BeanMap;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BeanChangeUtil<T> {

    /**
     * 对比两个实体类
     * @param oldBean
     * @param newBean
     * @return 返回不同值的集合
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Map<String, Object> contrastObj(Object oldBean, Object newBean) {
        StringBuilder str = new StringBuilder();
        Map<String, Object> stringObjectMap = new HashMap<>(64);
        T pojo1 = (T) oldBean;
        T pojo2 = (T) newBean;
        try {
            // 通过反射获取类的类类型及字段属性
            Class clazz = pojo1.getClass();
            Field[] fields = clazz.getDeclaredFields();
            int i = 1;
            for (Field field : fields) {
                // 排除序列化属性
                if ("serialVersionUID".equals(field.getName())) {
                    continue;
                }
                PropertyDescriptor pd = null;
                try {
                    pd = new PropertyDescriptor(field.getName(), clazz);
                    // 获取对应属性值
                    Method getMethod = pd.getReadMethod();
                    Object o1 = getMethod.invoke(pojo1);
                    Object o2 = getMethod.invoke(pojo2);
                    if (o2 == null) {
                        continue;
                    }
                    if (o1 == null && o2 != null){
                        stringObjectMap.put(field.getName(), o2);
                        i++;
                    }else if (!o1.toString().equals(o2.toString())) {
                        str.append(i + "、字段名称:" + field.getName() + ",旧值:" + o1 + ",新值:" + o2 + ";");
                        stringObjectMap.put(field.getName(), o2);
                        i++;
                    }
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                    System.out.println(field.toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return stringObjectMap;
    }

    /**
     * 对List集合对象合并
     * @param objects
     * @return 返回一个合并后的对象
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Map<String, Object> mergeObj(List<Object> objects) {

        Map<String, Object> stringObjectMap = new HashMap<>(128);
        for (Object object : objects){
            T pojo = (T) object;
            // 通过反射获取类的类类型及字段属性
            Class clazz = pojo.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 排除序列化属性
                try {
                    if ("serialVersionUID".equals(field.getName())) {
                        continue;
                    }
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                    Method getMethod = pd.getReadMethod();
                    Object o = getMethod.invoke(pojo);
                    if (o != null){
                        stringObjectMap.put(field.getName(), o);
                    }
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return stringObjectMap;
    }

    /**
     * map转对象
     * @param source
     * @param instance
     * @return
     */
    public Object mapToBean(Map<String, Object> source, Class instance) {
        if (source == null)
            return null;
        Object obj = null;
        try {
            obj = instance.newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                if (setter != null) {
                    setter.invoke(obj, source.get(property.getName()));
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 将map装换为javabean对象
     *
     * @param map
     * @param bean
     * @return
     */
    public static <T> T mapToBean(Map<String, Object> map, T bean) {
        BeanMap beanMap = BeanMap.create(bean);
        beanMap.putAll(map);
        return bean;
    }

    /**
     * 对象转map
     * @param bean
     * @param <T>
     * @return
     */
    public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = Maps.newHashMap();
        if (bean != null) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * 将List<T>转换为List<Map<String, Object>>
     *
     * @param objList
     * @return
     */
    public static <T> List<Map<String, Object>> objectsToMaps(List<T> objList) {
        List<Map<String, Object>> list = Lists.newArrayList();
        if (objList != null && objList.size() > 0) {
            Map<String, Object> map = null;
            T bean = null;
            for (int i = 0, size = objList.size(); i < size; i++) {
                bean = objList.get(i);
                map = beanToMap(bean);
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 将List<Map<String,Object>>转换为List<T>
     *
     * @param maps
     * @param clazz
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static <T> List<T> mapsToObjects(List<Map<String, Object>> maps, Class<T> clazz)
            throws InstantiationException, IllegalAccessException {
        List<T> list = Lists.newArrayList();
        if (maps != null && maps.size() > 0) {
            Map<String, Object> map = null;
            T bean = null;
            for (int i = 0, size = maps.size(); i < size; i++) {
                map = maps.get(i);
                bean = clazz.newInstance();
                mapToBean(map, bean);
                list.add(bean);
            }
        }
        return list;
    }


    /**
     * 从集合中提取值
     * @param instance
     * @param fieldNameMaps
     * @param queryList
     * @return 一个对象
     */
    public Object setBeanValue(Class instance, Map<String, String> fieldNameMaps, List<Map<String, Object>> queryList) {
        if (queryList == null)
            return null;
        Object obj = null;
        try {
            obj = instance.newInstance();
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                Method setter = property.getWriteMethod();
                if (setter != null) {
                    // 获取字段的值
                    Map<String, Object> fieldMap = getFieldValue(property.getName(), fieldNameMaps, queryList);
                    if (fieldMap != null){
                        setter.invoke(obj, fieldMap.get("dvalue").toString());
                        for (PropertyDescriptor propertyUtil : propertyDescriptors) {
                            Method setterUtil = propertyUtil.getWriteMethod();
                            if (propertyUtil.getName().equals(property.getName()+"Unit")){
                                setterUtil.invoke(obj, fieldMap.get("unit").toString());
                            }
                        }
                    }
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return obj;
    }

    private Map<String, Object> getFieldValue(String name, Map<String, String> fieldNameMaps, List<Map<String, Object>> queryList) {
        if (name == null && fieldNameMaps == null && queryList == null)return null;
        if (queryList.size() > 0){
            for (Map<String, Object> objectMap : queryList){
                for (Map.Entry<String, String> fieldName : fieldNameMaps.entrySet()){
                    if (fieldName.getValue().equals(objectMap.get("dataType"))){
                        if (name.equals(fieldName.getKey())){
                            return objectMap;
                        }
                    }
                }
            }
        }
        return null;
    }
    /**
     * 该方法是用于相同对象不同属性值的合并，如果两个相同对象中同一属性都有值，那么sourceBean中的值会覆盖tagetBean重点的值
     * @param sourceBean    被提取的对象bean
     * @param targetBean    用于合并的对象bean
     * @return targetBean,合并后的对象
     */
    public Object combineSydwCore(Object sourceBean,Object targetBean){
        Class sourceBeanClass = sourceBean.getClass();
        Class targetBeanClass = targetBean.getClass();

        Field[] sourceFields = sourceBeanClass.getDeclaredFields();
        Field[] targetFields = targetBeanClass.getDeclaredFields();
        for(int i=0; i<sourceFields.length; i++){
            Field sourceField = sourceFields[i];
            if (Modifier.isStatic(sourceField.getModifiers())){
                continue;
            }
            Field targetField = targetFields[i];
            if (Modifier.isStatic(targetField.getModifiers())){
                continue;
            }
            sourceField.setAccessible(true);
            targetField.setAccessible(true);
            try {
                if( !(sourceField.get(sourceBean) == null) &&  !"serialVersionUID".equals(sourceField.getName().toString())){
                    targetField.set(targetBean,sourceField.get(sourceBean));
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return targetBean;
    }
}
